package com.ice.work.moment.crawler.processor;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.honeybee.cloud.framework.common.constant.CommonSystemConstant;
import com.honeybee.cloud.framework.common.enums.DataStatusEnum;
import com.honeybee.cloud.framework.common.idwork.IdWorker;
import com.ice.work.moment.crawler.service.IShareService;
import com.ice.work.moment.crawler.service.ITradingService;
import com.ice.work.moment.facade.crawler.analytical.TradingAnalyticalObject;
import com.ice.work.moment.facade.crawler.dto.ShareDTO;
import com.ice.work.moment.facade.crawler.enums.TradingEnum;
import com.ice.work.moment.facade.crawler.mapper.AnalyticalObjectConvertMapper;
import com.ice.work.moment.facade.crawler.model.Trading;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description A股详情
 * @Author DELL
 * @Create 2019-04-29
 * @Since 1.0.0
 */
@Slf4j
@Component
@SuppressWarnings("all")
public class TradingProcessor extends BaseProcessor implements PageProcessor {

    @Autowired
    private IdWorker idWorker;
    @Autowired
    private IShareService shareService;
    @Autowired
    private ITradingService tradingService;

    @Override
    public void process(Page page) {
        Html html = page.getHtml();
        log.info("交易内容原文:{}", html.get());
        //获取股票代码
        String codeValue = html.xpath("//*[@id='act_quote']/table/tbody/tr/td[1]/table/tbody/tr[1]/td/table/tbody/tr[1]/td/div[1]/text()").get();
        if (StringUtils.isEmpty(codeValue)) {
            log.info("无法获取到股票代码");
            return;
        }
        String code = codeValue.substring(codeValue.indexOf("(") + 1, codeValue.indexOf(")"));
        ShareDTO shareDTO = shareService.findByShareCode(code);
        if (Objects.isNull(shareDTO)) {
            log.error("无法获取到股票代码:{}", code);
            return;
        }

        //获取交易详情
        List<Selectable> trSelectableList = html.xpath("//*[@id='act_quote']/table/tbody/tr/td[1]/table/tbody/tr[1]/td/table/tbody/tr").nodes();
        if (CollectionUtils.isEmpty(trSelectableList) || CollectionUtils.size(trSelectableList) == 1) {
            return;
        }
        int i = 1;
        do {
            try {
                Selectable trSelectable = trSelectableList.get(i);
                i++;
                log.info("爬取交易内容:{}", trSelectable.toString());
                TradingAnalyticalObject tradingAnalyticalObject = new TradingAnalyticalObject();
                tradingAnalyticalObject = getValues(tradingAnalyticalObject, trSelectable);
                log.info("交易内容处理结果:{}", tradingAnalyticalObject);
                Trading trading = AnalyticalObjectConvertMapper.INSTANCE.toModel(tradingAnalyticalObject);
                if (Objects.isNull(trading)) {
                    continue;
                }
                //一天最新的，可能没有开盘，数据不需要
                if (Objects.isNull(trading.getRecentQuotation()) || trading.getRecentQuotation() <= 0) {
                    continue;
                }
                trading.setId(idWorker.nextId());
                trading.setShareId(shareDTO.getId());
                trading.setDataStatus(DataStatusEnum.VALID.key);
                trading.setCreateAt(new Date());
                tradingService.saveOrUpdate(trading);
            } catch (Exception e) {
                log.error("爬取交易详情异常", e);
            }

        } while (i < trSelectableList.size());

    }

    /**
     * 获取列值
     *
     * @param trSelectable
     * @return
     */
    private TradingAnalyticalObject getValues(TradingAnalyticalObject obj, Selectable trSelectable) {
        Class clazz = obj.getClass();
        Field[] fields = ReflectUtil.getFields(clazz);
        Method[] methods = ReflectUtil.getMethods(clazz);
        Map<String, Field> fieldMap = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, a -> a, (k1, k2) -> k1));
        Map<String, Method> methodMap = Arrays.stream(methods).collect(Collectors.toMap(Method::getName, a -> a, (k1, k2) -> k1));
        List<Selectable> tdSelectableList = trSelectable.xpath("/tr/td/table/tbody/tr/td").nodes();
        Map<String, String> resultMap = Maps.newConcurrentMap();
        for (int j = 0; j < tdSelectableList.size(); j++) {
            try {
                String value = null;
                StringBuilder key = new StringBuilder();
                Selectable tdSelectable = tdSelectableList.get(j);

                //font里面的内容
                List<Selectable> fontSelectTableList = tdSelectable.xpath("//font").nodes();
                if (CollectionUtils.isNotEmpty(fontSelectTableList)) {
                    for (int i = 1; i <= fontSelectTableList.size(); i++) {
                        String path = "//font[" + i + "]";
                        List<Selectable> selectableList = tdSelectable.xpath(path).nodes();
                        if (CollectionUtils.isNotEmpty(selectableList)) {
                            value = tdSelectable.xpath(getTextPath(path)).get();
                            key.setLength(0);
                            key.append(j).append(i);
                            resultMap.put(key.toString(), value);
                        }
                    }
                }

                //span里面的内容
                List<Selectable> spanSelectTableList = tdSelectable.xpath("//span").nodes();
                if (CollectionUtils.isNotEmpty(spanSelectTableList)) {
                    for (int i = 0; i < spanSelectTableList.size(); i++) {
                        Selectable tSpanSelectTable = spanSelectTableList.get(i);
                        //span里面的内容
                        List<Selectable> tSpanSelectTableList = tSpanSelectTable.xpath("/span").nodes();
                        for (int m = 1; m <= tSpanSelectTableList.size(); m++) {
                            value = tSpanSelectTable.xpath("/span/text()").get();
                            if (value.matches(".*[-|\\+].*%$")) {
                                //这里是跌了的解析
                                String[] values = value.split("[\\+|-]");
                                for (int k = 0; k < values.length; k++) {
                                    if (StringUtils.isEmpty(values[k])) {
                                        continue;
                                    }
                                    key.setLength(0);
                                    key.append(j).append(i).append(m).append(k);
                                    resultMap.put(key.toString(), value.contains(CommonSystemConstant.HYPHEN) ? CommonSystemConstant.HYPHEN + values[k] : values[k]);
                                }
                            } else if (value.matches("\\d+\\.\\d+\\.\\d+%$")) {
                                //这里是跌了的解析 1 2 跟跌的对应
                                key.setLength(0);
                                key.append(j).append(i).append(m).append(1);
                                String tValue = value.substring(0, value.indexOf(".") + 3);
                                resultMap.put(key.toString(), tValue);

                                key.setLength(0);
                                key.append(j).append(i).append(m).append(2);
                                tValue = value.substring(value.indexOf(".") + 3);
                                resultMap.put(key.toString(), tValue);
                            } else {
                                //这里是通用的解析
                                String path = "//span[" + m + "]";
                                List<Selectable> selectableList = tSpanSelectTable.xpath(path).nodes();
                                if (CollectionUtils.isNotEmpty(selectableList)) {
                                    value = tSpanSelectTable.xpath(getTextPath(path)).get();
                                } else {
                                    value = tSpanSelectTable.xpath("//span/text()").get();
                                }
                                key.setLength(0);
                                key.append(j).append(i).append(m);
                                resultMap.put(key.toString(), value);
                            }

                        }
                    }


                }

                String xpath = "//td";

                //其它的在td里面的内容
                List<Selectable> tdSelectTableList = tdSelectable.xpath(xpath).nodes();
                if (CollectionUtils.isNotEmpty(tdSelectTableList)) {
                    value = tdSelectable.xpath(getTextPath(xpath)).get();
                    key.setLength(0);
                    key.append(j);
                    resultMap.put(key.toString(), value);
                    continue;
                }


            } catch (Exception e) {
                log.error("爬取A股交易详情内容处理异常", e);
            }
        }
        log.info("A股交易详情内容全部处理结果:{}", resultMap);
        resultMap.forEach((key, value) -> {
            try {
                String code = TradingEnum.getCodeByKey(key);
                if (Objects.nonNull(code)) {
                    Field field = fieldMap.get(code);
                    if (Objects.nonNull(field)) {
                        Method method = methodMap.get(StrUtil.genSetter(field.getName()));
                        if (Objects.nonNull(method)) {
                            method.invoke(obj, StrUtil.trim(value));
                        }
                    }
                }
            } catch (Exception e) {
                log.error("爬取A股交易详情处理异常", e);
            }
        });

        return obj;
    }

    private String getTextPath(String path) {
        String textPath = path + "/text()";
        return textPath;
    }


}
